package bll

import (
	"context"
	"encoding/json"
	"fmt"
	"gitlab.local/backend/proto/dto"
	"golang.org/x/sync/errgroup"
	"manager/client/grpc"
	log "manager/collector/logger"
	"manager/event"
	"manager/lib/trace_log"
	SignalPo "manager/model/signal"
	"manager/store/redis"
	"manager/utils"
	"manager/utils/goroutine_pool"
	"strings"
	"time"
)

const (
	// DevicePowerOnStatusKey 设备状态
	DevicePowerOnStatusKey = "device_status:device_power"
	// DeviceLocationKey 骑行记录
	DeviceLocationKey = "device_location"
)

var DeviceStatus = &deviceStatus{}

// DeviceStatus 设备状态
type deviceStatus struct {
}

func (d *deviceStatus) init() func() {
	return func() {}
}

func (d *deviceStatus) onEvent(data *event.Data) {
	if data == nil || (data.Type != event.Event_Power_On && data.Type != event.Event_Power_Off && data.Type != event.Event_Power_On_Cmd &&
		data.Type != event.Event_Power_Off_Cmd && data.Type != event.Event_Bike_Online && data.Type != event.Event_Bike_Offline) {
		return
	}

	_data, _ := json.Marshal(data)
	log.Info("---------------- deviceCyclingReport onEvent data:", string(_data))

	// 一键启动命令
	if data.Type == event.Event_Power_On_Cmd {
		// 解析参数
		obj := data.Data.(*event.BikePowerOnCmd)
		if obj == nil {
			log.Error("deviceStatus BikePowerOnCmd onEvent err")
			return
		}

		// 添加一键启动
		key := fmt.Sprintf("%v", obj.BikeId)
		value := fmt.Sprintf("%v_%v", obj.UserId, "off")

		bikeInfo, _ := CacheBike.GetBikeInfoById(obj.BikeId)
		if bikeInfo != nil && bikeInfo.SNCode != "" {
			trace_log.DebugLogger(bikeInfo.SNCode, "bll deviceStatus app 一键启动 bikeId:", obj.BikeId, "userId:", obj.UserId, "key:", key, "value:", value)
		}
		if err := redis.KV.AddValueWithExpireTime(context.Background(), DevicePowerOnStatusKey, key, fmt.Sprintf("%v", value), time.Second*30); err != nil {
			log.Errorf("deviceStatus AddValueWithExpireTime err:%v", err)
		}

		return
	}

	// 一键关闭
	if data.Type == event.Event_Power_Off_Cmd {
		obj := data.Data.(*event.BikePowerOffCmd)
		if obj == nil {
			log.Error("deviceStatus BikePowerOnCmd onEvent err")
			return
		}

		/*		// 添加一键启动
				key := fmt.Sprintf("%v", obj.BikeId)
				if err := redis.KV.DelValue(context.Background(), DevicePowerOnStatusKey, key); err != nil {
					log.Errorf("deviceStatus DelValue err:%v", err)
				}*/
		return
	}

	// 上电
	if data.Type == event.Event_Power_On {
		// 解析参数
		obj := data.Data.(*event.BikePowerOn)
		if obj == nil {
			log.Error("deviceStatus onEvent err")
			return
		}

		// 车辆上电
		bikeInfo, _ := CacheBike.GetBikeInfoById(obj.EbikeId)
		if bikeInfo != nil && bikeInfo.SNCode != "" {
			trace_log.DebugLogger(bikeInfo.SNCode, "bll deviceStatus Event_Power_On onEvent", "上电")
			// 上电锁车检查
			goroutine_pool.GetPool().Push(nil, func(data interface{}) error {
				if err := LoseLock.DoLock(bikeInfo.SNCode); err != nil {
					trace_log.DebugLogger(bikeInfo.SNCode, "bll deviceStatus Event_Power_On onEvent", "上线锁车失败")
				}
				return nil
			})
		}

		// 加分布式锁
		conn := redis.KV.GetRedisPool().Get()
		lock := &redis.TRedLock{}
		bSuccess, _ := lock.Lock(conn, fmt.Sprintf("poweron_%v", obj.EbikeId), 10)
		if !bSuccess {
			log.Errorf("deviceCyclingReport lock fail")
			return
		}
		defer lock.UnLock(conn)

		var value string
		isOn, userId := d.GetPowerOnUser(obj.EbikeId)
		if isOn {
			return
		}

		key := fmt.Sprintf("%v", obj.EbikeId)
		value = fmt.Sprintf("%v_%v", userId, "on")

		if bikeInfo != nil && bikeInfo.SNCode != "" {
			trace_log.DebugLogger(bikeInfo.SNCode, "------------ bll deviceStatus 车辆启动成功 bikeId:", obj.EbikeId, " userId:", userId, " value:", value, " isOn:", isOn)
		}
		if err := redis.KV.AddValueWithExpireTime(context.Background(), DevicePowerOnStatusKey, key, value, time.Second*60); err != nil {
			log.Errorf("deviceStatus AddValueWithExpireTime err:%v", err)
		}

		// 上电完成
		event.Emit(&event.Data{
			Type: event.Event_Power_On_Finish,
			Data: &event.BikePowerOn{EbikeId: obj.EbikeId},
		})
		return
	}

	// 下电
	if data.Type == event.Event_Power_Off {
		// 解析参数
		obj := data.Data.(*event.BikePowerOff)
		if obj == nil {
			log.Error("deviceStatus onEvent err")
			return
		}

		// 加分布式锁
		conn := redis.KV.GetRedisPool().Get()
		lock := &redis.TRedLock{}
		bSuccess, _ := lock.Lock(conn, fmt.Sprintf("poweroff_%v", obj.EbikeId), 10)
		if !bSuccess {
			log.Errorf("deviceCyclingReport lock fail")
			return
		}
		defer lock.UnLock(conn)

		isOn, userId := d.GetPowerOnUser(obj.EbikeId)
		if !isOn {
			return
		}

		// 车辆下电
		bikeInfo, _ := CacheBike.GetBikeInfoById(obj.EbikeId)
		if bikeInfo != nil && bikeInfo.SNCode != "" {
			trace_log.DebugLogger(bikeInfo.SNCode, "------- bll deviceStatus Event_Power_Off 车辆下电 bikeId:", obj.EbikeId, " userId:", userId, " isOn:", isOn)
		}

		key := fmt.Sprintf("%v", obj.EbikeId)

		// 下电完成
		goroutine_pool.GetPool().Push(nil, func(data interface{}) error {
			defer utils.ExceptionCatch()
			// 下电完成
			event.Emit(&event.Data{
				Type: event.Event_Power_Off_Finish,
				Data: &event.BikePowerOff{EbikeId: obj.EbikeId},
			})

			// 下电
			if err := redis.KV.DelValue(context.Background(), DevicePowerOnStatusKey, key); err != nil {
				log.Errorf("deviceStatus AddValueWithExpireTime err:%v", err)
			}
			return nil
		})
		return
	}

	// 上线
	if data.Type == event.Event_Bike_Online {
		// 解析参数
		obj := data.Data.(*event.BikeOnline)
		if obj == nil {
			log.Error("deviceStatus Event_Bike_Online onEvent err")
			return
		}

		log.Info("deviceStatus Event_Bike_Online onEvent", obj.BikeId)
		// 上线执行上报失窃检查
		bikeInfo, _ := CacheBike.GetBikeInfoById(obj.BikeId)
		if bikeInfo.ID > 0 {
			trace_log.DebugLogger(bikeInfo.SNCode, "车辆上线 执行上线相关操作")
			go func() {
				if err := LoseLock.DoLock(bikeInfo.SNCode); err != nil {
					trace_log.DebugLogger(bikeInfo.SNCode, "bll deviceStatus Event_Bike_Online onEvent", "上线锁车失败")
				}
			}()

		}

		// 查询电池信息
		var errG errgroup.Group
		errG.Go(func() error {
			ret, err := SignalV2.GetMsgFromDevice("", &SignalPo.GetMessageReq{
				EbikeId: obj.BikeId,
				Cmd:     "Battery",
			})

			trace_log.DebugLogger(bikeInfo.SNCode, "GetMsgFromDevice Battery data:", utils.ToJsonString(ret), " err:", err)
			return nil
		})

		errG.Go(func() error {
			ret, err := SignalV2.GetMsgFromDevice("", &SignalPo.GetMessageReq{
				EbikeId: obj.BikeId,
				Cmd:     "Location",
			})
			trace_log.DebugLogger(bikeInfo.SNCode, "GetMsgFromDevice Location data:", utils.ToJsonString(ret), " err:", err)
			return nil
		})

		errG.Go(func() error {
			ret, err := SignalV2.GetMsgFromDevice("", &SignalPo.GetMessageReq{
				EbikeId: obj.BikeId,
				Cmd:     "Controller",
			})

			trace_log.DebugLogger(bikeInfo.SNCode, "GetMsgFromDevice Controller data:", utils.ToJsonString(ret), " err:", err)
			return nil
		})

		errG.Go(func() error {
			defer utils.ExceptionCatch()
			ret, err := SignalV2.GetMsgFromDevice("", &SignalPo.GetMessageReq{
				EbikeId: obj.BikeId,
				Cmd:     "FirmwareVersion",
			})

			trace_log.DebugLogger(bikeInfo.SNCode, "GetMsgFromDevice FirmwareVersion data:", utils.ToJsonString(ret), " err:", err)
			if err != nil {
				return err
			}

			// 同步设备信息到设备影子
			event.Emit(&event.Data{
				Type: event.Event_Mq_SyncDevice,
				Data: &event.MqSyncDevice{
					Sn:         bikeInfo.SNCode,
					UpdateType: dto.EnUpdateType_ATTRIBUTE,
					MapValue: map[string]interface{}{
						"firmware_version": ret.(*dto.FirmwareVersionReply).FirmwareVersion,
					},
				},
			})

			ctx, _ := context.WithTimeout(context.Background(), time.Minute*3)
			_, err = grpc.OCmd.OfflineUpgrade(ctx, &dto.OfflineUpgradeRequest{Sn: bikeInfo.SNCode})
			if err != nil {
				trace_log.DebugLogger(bikeInfo.SNCode, "发送车辆延迟OTA指令失败 err:", err)
			} else {
				trace_log.DebugLogger(bikeInfo.SNCode, "发送车辆延迟OTA指令成功")
			}
			// 触发ota程序升级
			//// 是否有升级计划
			//u, err := Ota.iFirmwaresTactic.FindUpgradePlanBySn(bikeInfo.SNCode, []int{1, 2, 3})
			//if err != nil {
			//  trace_log.DebugLogger(bikeInfo.SNCode, "bll deviceStatus Event_Bike_Online iFirmwaresTactic FindUpgradePlanBySn err:", err)
			//  return nil
			//}
			//if u == nil || u.FirmwareId <= 0 {
			//  trace_log.DebugLogger(bikeInfo.SNCode, "no upgrade version")
			//  return nil
			//}
			//
			//// 对比查询的版本号和计划升级的版本号确定是否升级成功
			//// 版本不一致认为升级失败
			//version := ret.(*dto.FirmwareVersionReply).FirmwareVersion
			//if u != nil {
			//  if u.Version != version {
			//    trace_log.DebugLogger(bikeInfo.SNCode, "target version:", u.Version, " current version:", version, " 车辆上线固件版本不一致 err:", Ota.OTAUpgradeFailed(bikeInfo.SNCode, Ota.GetInfo(100)))
			//  } else {
			//    trace_log.DebugLogger(bikeInfo.SNCode, "车辆上线固件版本一致 err:", Ota.OTAUpgradeSuccess(bikeInfo.SNCode, version))
			//  }
			//}
			return nil
		})

		err := errG.Wait()
		if err != nil {
			trace_log.DebugLogger(bikeInfo.SNCode, "bll deviceStatus Event_Bike_Online onEvent", "上线查询相关信息失败")
		}

		// 执行未执行的命令
		err = DelayCommand.ExecCommand(bikeInfo.SNCode)
		if err != nil {
			log.Errorf("deviceStatus Event_Bike_Online onEvent err:%v", err)
		}
		return
	}

	// 下线
	if data.Type == event.Event_Bike_Offline {
		// 解析参数
		obj := data.Data.(*event.BikeOffline)
		if obj == nil {
			log.Error("deviceStatus Event_Bike_Offline onEvent err")
			return
		}

		log.Info("deviceStatus Event_Bike_Online onEvent", obj.BikeId)
		return
	}
}

// GetPowerStatus 获取启动状态 0关闭 1启动中 2启动成功
func (d *deviceStatus) GetPowerStatus(bikeId int64) int {
	key := fmt.Sprintf("%v", bikeId)
	var value string
	redis.KV.GetValue(context.Background(), DevicePowerOnStatusKey, key, &value)
	rets := strings.Split(value, "_")
	if len(rets) != 2 {
		return 0
	}
	if len(rets) == 0 {
		log.Errorf("deviceStatus GetPowerStatus one button start failed")
		return 0
	}

	if rets[1] == "off" {
		return 1
	}

	if rets[1] == "on" {
		return 2
	}

	return 0
}

// IsPowerOn 是否一键启动成功
func (d *deviceStatus) IsPowerOn(bikeId int64) bool {
	key := fmt.Sprintf("%v", bikeId)
	var value string
	redis.KV.GetValue(context.Background(), DevicePowerOnStatusKey, key, &value)
	rets := strings.Split(value, "_")
	if len(rets) != 2 {
		return false
	}
	if len(rets) == 0 {
		log.Errorf("deviceStatus IsPowerOn one button start failed")
		return false
	}

	return rets[1] == "on"
}

// GetPowerOnUser 获取开机用户
func (d *deviceStatus) GetPowerOnUser(bikeId int64) (bool, int64) {
	key := fmt.Sprintf("%v", bikeId)
	var value string
	redis.KV.GetValue(context.Background(), DevicePowerOnStatusKey, key, &value)
	rets := strings.Split(value, "_")
	if len(rets) != 2 {
		managerId := UserEbike.GetManagerByBikeId(bikeId)
		return false, managerId
	}

	userId := utils.StrToInt64(rets[0])
	if utils.StrToInt64(rets[0]) == 0 {
		userId = UserEbike.GetManagerByBikeId(bikeId)
	}

	return rets[1] == "on", userId

}
